
#include <fstream>

#include "inference_engine.hpp"
#include "knowledge_base.hpp"
#include "ilp.hpp"

#include "henry.hpp"

/* The ILP class implementation */
ilp::solver_t::solver_t() {

  SCIPsetMessagehdlr(NULL);
  
  SCIPcreate( &m_p_scip );
  SCIPincludeDefaultPlugins( m_p_scip );

  SCIPcreateProb(  m_p_scip, "the_weighted_abduction", NULL, NULL, NULL, NULL, NULL, NULL, NULL );
  SCIPsetObjsense( m_p_scip, SCIP_OBJSENSE_MINIMIZE );
  
}

ilp::solver_t::~solver_t() {
  
  release();
  
}

void ilp::solver_t::solve() {

  SCIPsolve( m_p_scip );

  /* Hmm... thanks. Let me see the results... */
  SCIP_SOL** p_solutions = SCIPgetSols( m_p_scip );

  for( int i=0; i<SCIPgetNSols( m_p_scip ); i++ ) {
    m_solutions.push_back( p_solutions[i] );
  }
  
}

void ilp::solver_t::release() {

  SCIPfreeTransform( m_p_scip );
  
  /* Free all the stored variables. */
  foreach( list<variable_t>, itr, m_variables )
    SCIPreleaseVar( m_p_scip, &(*itr) );
  
  foreach( list<constraint_t>, itr, m_constraints )
    SCIPreleaseCons( m_p_scip, &(*itr) );
  
  SCIPfree( &m_p_scip );
  
}

void ilp::solver_t::del_variable( variable_t var ) {

  SCIPdelVar( m_p_scip, var );
  
}

void ilp::solver_t::add_constraint( constraint_template_t &c ) {

  constraint_t cons;

  /* Check NULL. */
  foreach( vector<variable_t>, iter_var, c.variables )
    if( NULL == *iter_var )
      { cmsg << v<1> << "Fatal: NULL constraint detected!" << endl; return; }

  if( CT_NO_MATTER == c.lhs ) c.lhs = -CT_NO_MATTER;
  
  SCIPcreateConsLinear( m_p_scip, &cons, "", c.variables.size(), &c.variables[0], &c.coefficients[0], c.lhs, c.rhs,
                        TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE );
  SCIPaddCons( m_p_scip, cons );

  m_constraints.push_back( cons );
  
}

ilp::variable_t ilp::solver_t::add_variable( double coefficient ) {

  variable_t var;

  SCIPcreateVar( m_p_scip, &var, "", 0.0, 1.0, coefficient, SCIP_VARTYPE_BINARY, TRUE, FALSE, NULL, NULL, NULL, NULL, NULL );
  SCIPaddVar(    m_p_scip, var );

  m_variables.push_back( var );
  
  return var;
  
}

